package org.shj.basic

object FuncDemo {
  def main(args : Array[String]) : Unit = {
    
    /**
     * 传名调用，只有在函数体内使用到传入的方法时，才会真正调用 
     * 可以看到先打印的是delay()里面的语句
     */
    def delay(t : => Long) { // 符号  => 表示传名调用
      println("in delay()")
      println("参数 t:" + t)
      t   //做为一个方法，又被调用了一次
    }
    
    def delay2(t : Long) {
      println("in delay()")
      println("参数 t:" + t)
    }
    
    def time() : Long = {
      val t = System.nanoTime()
      println("in time() method")
      return t
    }
    
    println("====== 测试传名调用 ======")
    delay(time())
    println("====== 测试传值调用 ======")
    delay2(time())
    
    
    println("====== 测试高阶函数 ======")
    //函数 f 和值 v 作为参数， 而函数 f 又调用了参数 v
    def apply(f: Int => String, v: Int) = f(v)    
    def layout[A](x: A) = "[" + x.toString() + "]"
    
    println(apply(layout, 10))
    
    
    println("====== 函数柯里化 ====== ")
    def reduce(x: Int) = (y : Int) => x-y
    val func = reduce(1)
    var result = func(2)
    println("Result: " + result)
    println("reduce(1)(2): " + reduce(1)(2))
    
    
    def curryReduce(a:Int)(b:Int) = a - b
    
    val reduce1 = curryReduce(1)_  // 下划线表示第二个参数的占位符
    println("reduce1: " + reduce1(2))  // -->  -1
    val reduce2 = curryReduce(2)_
    println("reduce2: " + reduce2(5))  //  -->  -3
    
    
    var factor = 3    
    //函数体依赖外部变量
    val multiple = (x : Int) => x * factor
    
    println("multiple(2): " + multiple(2))
    factor = 4
    println("multiple(3): " + multiple(3))
    
    // sayHi 后面的 _ 表示把函数赋值给一个变量，可以简单理解为 给 sayHi 函数取了一个叫做 hi 的别名 
    val hi = sayHi _ 
    hi("zhuyin")
    
    val f = (name : String) => println("hi " + name)
    f("yangmi")
    
    //函数的返回类型是一个函数时，返回的函数可以使用上层函数的参数。
    def funct(message : String) = (name : String) => println(message + ": " + name)
    def getName(func : (String) => Unit, name : String){//把函数作为参数
      funct(name)
    }
    
    getName(f, "xuruyun");
    
    Array((1 to 10): _*).map{(item : Int) => 2 * item}.foreach( x => print(x+ " "))
    
    funct("Hello")("Java") //Currying 函数写法
    //上面一句可以拆分为下面两句
    val rlt = funct("Hello")
    rlt("Java")
    
  }
  
  
  
  def sayHi(name : String){
    println("hi " + name)
  }
}